#ifndef __M_LOG_H__
#define __M_LOG_H__
#include "buffer.hpp"
#include "util.hpp"
#include "level.hpp"
#include "format.hpp"
#include "sink.hpp" 
#include "looper.hpp"
#include <atomic>
#include <mutex>
#include <memory>
#include <cstdarg>
#include <cstdlib>
#include <unordered_map>
#include <utility>
/*采用建造者模式*/

namespace mylog{
class Logger{
    public:
using ptr=std::shared_ptr<Logger>;
Logger(const std::string &logger_name,
    Formatter::ptr formatter,
    std::vector<LogSink::ptr> sinks, 
LogLevel::value limit_level=LogLevel::value::DEBUG ):
_logger_name(logger_name),
_limit_level(limit_level),
_formatter(formatter),
_sinks(sinks){}
virtual ~Logger(){}
/*日志器类型（同步异步）*/
enum class Type {
     LOGGER_SYNC = 0,  //同步
     LOGGER_ASYNC      //异步
     };
     std::string& name(){
        return _logger_name;
     }
/*完成构造日志消息对象过程并进行格式化，得到格式化后的日志消息字符串--然后调用Log进行落地输出，*/
void debug(const std::string &file,size_t line,const std::string &fmt,...){//file，line必需由用户传入，不定参根据 fmt (payload的fmt)字符串中的格式说明符进行格式化输出。
//1.判断当前日志是否达到输出等级
if(LogLevel::value::DEBUG<_limit_level)return;
//2.对fmt格式化字符串和不定参进行字符串组织，得到(payload)
va_list ap;  //可变参数列表变量
va_start(ap,fmt);  ////对ap进行初始化，让其指向这里固定参数fmt后的第一个可变参数地址
char* res;
int ret=vasprintf(&res,fmt.c_str(),ap);//将格式化的可变参数输出到动态分配的字符串
va_end(ap);
if(ret==-1){
    std::cout<<"vasprintf fail"<<std::endl;
    return;
}
//3.构造LogMsg对象
LogMsg msg(LogLevel::value::DEBUG,line,file,_logger_name,res);
//4.通过formatter对LogMsg进行格式化，得到最终字符串
std::stringstream ss;

_formatter->format(ss,msg);

//5.调用日志落地函数log，进行日志落地
log(ss.str().c_str(),ss.str().size());
free(res);
}

void info(const std::string &file,size_t line,const std::string &fmt,...){
    if(LogLevel::value::INFO < _limit_level) return;

va_list ap;
va_start(ap, fmt);
char* res;
int ret = vasprintf(&res, fmt.c_str(), ap);
va_end(ap);
if (ret == -1) {
    std::cout << "vasprintf fail" << std::endl;
    return;
}

LogMsg msg(LogLevel::value::INFO, line, file, _logger_name, res);

std::stringstream ss;
_formatter->format(ss, msg);

log(ss.str().c_str(), ss.str().size());
free(res);
}

void warn(const std::string &file,size_t line,const std::string &fmt,...){
    if(LogLevel::value::WARN < _limit_level) return;

va_list ap;
va_start(ap, fmt);
char* res;
int ret = vasprintf(&res, fmt.c_str(), ap);
va_end(ap);
if (ret == -1) {
    std::cout << "vasprintf fail" << std::endl;
    return;
}

LogMsg msg(LogLevel::value::WARN, line, file, _logger_name, res);

std::stringstream ss;
_formatter->format(ss, msg);

log(ss.str().c_str(), ss.str().size());
free(res);
}
void error(const std::string &file,size_t line,const std::string &fmt,...){
    if(LogLevel::value::ERROR < _limit_level) return;

va_list ap;
va_start(ap, fmt);
char* res;
int ret = vasprintf(&res, fmt.c_str(), ap);
va_end(ap);
if (ret == -1) {
    std::cout << "vasprintf fail" << std::endl;
    return;
}

LogMsg msg(LogLevel::value::ERROR, line, file, _logger_name, res);

std::stringstream ss;
_formatter->format(ss, msg);

log(ss.str().c_str(), ss.str().size());
free(res);
}



void fatal(const std::string &file,size_t line,const std::string &fmt,...){
    if(LogLevel::value::FATAL < _limit_level) return;

va_list ap;
va_start(ap, fmt);
char* res;
int ret = vasprintf(&res, fmt.c_str(), ap);
va_end(ap);
if (ret == -1) {
    std::cout << "vasprintf fail" << std::endl;
    return;
}

LogMsg msg(LogLevel::value::FATAL, line, file, _logger_name, res);

std::stringstream ss;
_formatter->format(ss, msg);

log(ss.str().c_str(), ss.str().size());
free(res);
}

protected:
/*纯虚函数，负责进行真正的落地输出部分*/
virtual void log(const char* data,size_t len)=0;
std::string _logger_name;  //日志器名称
std::atomic<LogLevel::value> _limit_level;  //限制输出等级,频繁访问或修改，设置成原子类型
Formatter::ptr _formatter;  //格式化模块对象
std::vector<LogSink::ptr> _sinks;  //落地方向数组
std::mutex _mutex;
};

//同步日志器
class SyncLogger:public Logger{
    public:
    SyncLogger(const std::string &logger_name,
    Formatter::ptr formatter,
    std::vector<LogSink::ptr> &sinks,
    LogLevel::value limit_level=LogLevel::value::DEBUG     
):
  Logger(logger_name,formatter,sinks,limit_level){}
    protected:
    void log(const char* data,size_t len)override{
        //加锁，保证线程安全
        std::unique_lock<std::mutex> lock(_mutex);
        if(_sinks.empty())return;
        for(auto &it:_sinks){
            it->log(data,len);
        }

    }
};

//异步日志器
class AsyncLogger:public Logger{
public:
AsyncLogger(const std::string &logger_name,
    Formatter::ptr &formatter,
    std::vector<LogSink::ptr> &sinks,
    LogLevel::value limit_level,
    AsyncType looper_type):
    Logger(logger_name,formatter,sinks,limit_level),
    _looper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::realLog, this, std::placeholders::_1),looper_type)){}
    //把 realLog 函数的第一个参数固定为 this，第二个参数使用占位符。
    //将数据写入缓冲区
    void log(const char* data,size_t len){
        _looper->push(data,len);
        //std::cout<<"log函数执行！"<<std::endl;
    }
    //将缓冲区中数据落地
    void realLog(Buffer &buf){
        for(auto &sink:_sinks){
            sink->log(buf.begin(),buf.readAbleSize());
        }
   
    }

    private:
      AsyncLooper::ptr _looper;
};



//抽象建造者基类
class LoggerBuilder{
public:
  using ptr=std::shared_ptr<LoggerBuilder>;
  LoggerBuilder():
  _level(LogLevel::value::DEBUG),
  _logger_type(Logger::Type::LOGGER_SYNC),
  _looper_type(AsyncType::ASYNC_SAFE)
  {}
  void buildLoggerName(const std::string& logger_name){_logger_name=logger_name;}
  void buildLoggerLevel(LogLevel::value level){_level=level;}
  void buildLoggerType(Logger::Type logger_type){_logger_type=logger_type;}
  void buildFormatter(const std::string& pattern){_formatter=std::make_shared<Formatter>(pattern);}
  template<typename SinkType,typename ...Args>
  void buildSink(Args &&...args){
    auto sink=SinkFactory::Create<SinkType>(std::forward<Args>(args)...);
    _sinks.push_back(sink);
}
void buildEnableUnsafeAsync(){_looper_type=AsyncType::ASYNC_UNSAFE;}
  virtual Logger::ptr build()=0;
protected:
AsyncType _looper_type;
 Logger::Type _logger_type;
 std::string _logger_name;
 LogLevel::value _level;
 Formatter::ptr _formatter;
 std::vector<LogSink::ptr> _sinks;  
};


//局部日志器的建造者
class LocalLoggerBuilder:public LoggerBuilder{
public:
/*零件设置好以后调用*/
Logger::ptr build()override{
  assert(!_logger_name.empty());//必须有日志器名称
  if(_formatter.get()==nullptr){    //如果不指定格式器，就使用默认的
    _formatter=std::make_shared<Formatter>("[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n");
  }
  if(_sinks.empty()){
    buildSink<StdoutSink>(); //未指定落地方式，就默认使用控制台打印的落地方式
  }
    Logger::ptr lp;
    if(_logger_type==Logger::Type::LOGGER_SYNC){
     lp=std::make_shared<SyncLogger>(_logger_name, _formatter,_sinks,_level);
   }else{
    lp=std::make_shared<AsyncLogger>(_logger_name, _formatter,_sinks,_level,_looper_type);
   }
   return lp;
}
};



//日志管理器（单例）
//对所有创建的日志器进行管理，并且可在全局任意位置获取同一个单例日志管理器，使用其中日志器
class LoggerManager{
public:
//获取日志管理器
static LoggerManager& getInstance(){
    static LoggerManager eton;
    return eton;
}
//添加日志器到日志管理器
void addLogger(Logger::ptr &logger){
    if(hasLogger(logger->name()))return;
    std::unique_lock<std::mutex> lock(_mutex);
    _loggers.insert(std::make_pair(logger->name(),logger));
    
}
//判断是否管理了指定名称的日志器
bool hasLogger(const std::string &name){
    auto it=_loggers.find(name);
    if(it==_loggers.end()){
        return false;
    }else{
        return true;
    }
}
//获取指定名称日志器
Logger::ptr getLogger(const std::string &name){
    return _loggers[name];
}
//返回默认日志器
Logger::ptr rootLogger(){
    return _root_logger;
}
private:
LoggerManager(){
    //生成默认日志器
    std::unique_ptr<mylog::LoggerBuilder> builder(new mylog::LocalLoggerBuilder());  //这里不能使用全局，不然有“鸡生蛋蛋生鸡”问题
    builder->buildLoggerName("root");
    _root_logger=builder->build();
    _loggers.insert(std::make_pair("root",_root_logger));
}
private:
std::mutex _mutex;
Logger::ptr _root_logger;//默认日志器
std::unordered_map<std::string,Logger::ptr> _loggers;//所管理的日志器数组
};

//全局日志器的建造者--在局部日志器建造者基础上新增功能：将日志器添加到单例对象
class GlobalLoggerBuilder:public LoggerBuilder{
    public:
    /*零件设置好以后调用*/
    Logger::ptr build()override{
      assert(!_logger_name.empty());//必须有日志器名称
      if(_formatter.get()==nullptr){    //如果不指定格式器，就使用默认的
        _formatter=std::make_shared<Formatter>();
      }
      if(_sinks.empty()){
        buildSink<StdoutSink>(); //未指定落地方式，就默认使用控制台打印的落地方式
      }
        Logger::ptr lp;
        if(_logger_type==Logger::Type::LOGGER_SYNC){
         lp=std::make_shared<SyncLogger>(_logger_name, _formatter,_sinks,_level);
       }else{
        lp=std::make_shared<AsyncLogger>(_logger_name, _formatter,_sinks,_level,_looper_type);
       }
       LoggerManager::getInstance().addLogger(lp);   //新增到日志管理器中
       return lp;
    }
    };
}
#endif